package com.lakeworks.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.lakeworks.common.annotation.RepeatSubmit;
import com.lakeworks.common.constant.HttpStatus;
import com.lakeworks.common.core.domain.AjaxResult;
import com.lakeworks.common.domain.channel.*;
import com.lakeworks.common.domain.system.OprDefeimg;
import com.lakeworks.common.domain.system.OprProductImg;
import com.lakeworks.common.enums.*;
import com.lakeworks.common.event.ReturnOrderEvent;
import com.lakeworks.common.exception.response.ResponseException;
import com.lakeworks.common.utils.BarcodeGenerator;
import com.lakeworks.common.utils.DateUtils;
import com.lakeworks.common.utils.StringUtils;
import com.lakeworks.common.utils.bean.BeanUtils;
import com.lakeworks.common.utils.tool.S3Tool;
import com.lakeworks.domain.*;
import com.lakeworks.domain.status.*;
import com.lakeworks.domain.vo.*;
import com.lakeworks.event.*;
import com.lakeworks.mapper.*;
import com.lakeworks.service.*;
import com.lakeworks.service.api.MerchantAsync;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.json.JsonObject;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.alibaba.fastjson.JSON.parseObject;
import static com.alibaba.fastjson.JSON.toJSONString;
import static com.lakeworks.common.core.domain.AjaxResult.*;
import static com.lakeworks.common.core.domain.AjaxResult.error;
import static com.lakeworks.common.enums.CategoryType.CLOTHES;
import static com.lakeworks.common.enums.CategoryType.SHOES;
import static com.lakeworks.common.enums.OprProductType.*;
import static com.lakeworks.common.enums.ResponseEnum.*;
import static com.lakeworks.common.utils.SecurityUtils.getUserName;
import static com.lakeworks.service.impl.OperateRecordUtil.*;
import static com.lakeworks.utils.NoCountPageUtil.getTotal;
import static java.lang.Boolean.TRUE;
import static java.util.Arrays.stream;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang3.StringUtils.*;

/**
 * 作业产品Service业务层处理
 *
 * @author lake
 * @date 2023-02-08
 */
@Service
public class OprProductServiceImpl implements IOprProductService {

    private static final Logger log = LoggerFactory.getLogger(OprProductServiceImpl.class);

    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Resource
    private OprProductMapper oprProductMapper;
    @Resource
    private OprPickupMapper oprPickupMapper;
    @Resource
    private OprMerchandiseMapper oprMerchandiseMapper;
    @Resource
    private OprProductImgMapper oprProductImgMapper;
    @Resource
    private OprDefeimgMapper oprDefeimgMapper;
    @Autowired
    private ISysAttachmentService sysAttachmentService;

    @Autowired
    private ISysRobotService sysRobotService;
    @Resource
    private OprAttachmentMapper oprAttachmentMapper;
    @Resource
    private OprShipmentMapper oprShipmentMapper;
    @Resource
    private ISysFrameService sysFrameService;
    @Autowired
    private ISysProductService sysProductService;
    @Autowired
    private IStaShipmentService staShipmentService;

    @Resource
    private OprRewashMapper oprRewashMapper;
    @Resource
    private OprMaterialMapper oprMaterialMapper;
    @Autowired
    private IStaProductService staProductService;
    @Autowired
    private S3Tool s3Tool;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private IStaPickupService staPickupService;
    @Autowired
    private MerchantAsync merchantAsync;
    @Autowired
    private IPostPackService postPackService;
    @Resource
    private SysMaterialMapper sysMaterialMapper;
    @Autowired
    private BarcodeGenerator barcodeGenerator;
    @Autowired
    private ISysChannelService channelService;

    private final Function<String,Boolean> getAutoStatus = code ->{
        AtomicBoolean b = new AtomicBoolean(false);
        ofNullable(sysRobotService.selectAutoByCode(code)).ifPresent(s->{
            if (s.getAuto().equals("0")) {
                b.set(true);
            }
        });
        return b.get();
    };



    /**
     * 添加产品附件
     */
    @Override
    public AjaxResult addProAttachment(Long oprProductId, Long sysAttachmentId,String complete) {
        OprProduct oprProduct = oprProductMapper.selectOprProductById(oprProductId);
        SysAttachment sysAttachment = sysAttachmentService.selectSysAttachmentById(sysAttachmentId);

        if (isNull(oprProduct) || isNull(sysAttachment))
            return error("产品或附件不存在");

        if (nonNull(oprProduct.getCompanionId()))
            return error("请在主产品上添加附件");

        log.info("添加产品附件，oprProductId：[{}]，oprAttachmentId：[{}]", oprProductId, sysAttachmentId);
        SysChannel sysChannel = channelService.selectSysChannelById(oprPickupMapper.selectOprPickupById(oprProduct.getPickupId()).getChannelId());

        OprAttachment oprAttachment = new OprAttachment()
                .setProductId(oprProductId)
                .setAttachmentId(sysAttachmentId)
                .setBarcode(barcodeGenerator.generator(parseObject(sysChannel.getConfig()).getString("barcode")))
                .setAttachTime(new Date())
                .setFrameNo(oprAttachmentMapper.listByPickupId(oprProduct.getPickupId())
                        .stream()
                        .filter(Predicate.not(OprAttachment::getIsScan))
                        .map(OprAttachment::getFrameNo)
                        .findAny()
                        .orElseGet(() -> sysFrameService.allocateFrame(true)))
                .setCreateBy(getUserName())
                .setModifyBy(getUserName());
        if(StringUtils.isNotBlank(complete) && complete.equals("2")){
            oprAttachment.setFlag(2);
        }
        if (oprAttachmentMapper.insertOprAttachment(oprAttachment) == 0)
            throw new ResponseException(ATTACHMENT_ADD_ERROR);
        return success(oprAttachmentMapper.listOprAttVoByProId(oprProduct.getId()));
    }

    /**
     * 删除产品附件
     */
    @Override
    public AjaxResult delProAttachment(Long oprProductId, Long oprAttachmentId) {
        OprProduct oprProduct = oprProductMapper.selectOprProductById(oprProductId);
        if (oprProduct == null)
            return error("产品不存在");
        log.info("删除产品附件，oprProductId：[{}]，oprAttachmentId：[{}]", oprProductId, oprAttachmentId);

        List<OprAttachmentVO> list = oprAttachmentMapper.listOprAttVoByProId(oprProduct.getId());
        if (list.stream().mapToLong(OprAttachmentVO::getId).noneMatch(oprAttachmentId::equals))
            return error("无此附件");
        oprAttachmentMapper.deleteOprAttachmentById(oprAttachmentId);
        if (list.size() == 1 && oprAttachmentMapper.selectOprAttachmentList(new OprAttachment().setFrameNo(list.get(0).getFrameNo()).setIsScan(false)).isEmpty())
            sysFrameService.releaseFrame(true, list.get(0).getFrameNo());

        return success(oprAttachmentMapper.listOprAttVoByProId(oprProduct.getId()));
    }

    /**
     * 总检-配附件
     */
    @Override
    public AjaxResult attsOfProduct(String barcode) {
        OprProduct oprProduct = queryByBarcode(barcode);
        if (oprProduct == null)
            return error("无效水洗码");
        List<OprAttachmentVO> oprAttachmentVOS = oprAttachmentMapper
                .listOprAttVoByProId(oprProduct.getCompanionId() == null ? oprProduct.getId() :  oprProduct.getCompanionId());
        if (oprAttachmentVOS.isEmpty())
            throw new ResponseException("此产品没有附件");
        log.info("总检-配附件，productBarcode：[{}]，oprAttachmentVOS：[{}]", oprProduct.getBarcode(), toJSONString(oprAttachmentVOS));
        CompanionInfo companionInfo = getCompanionVO(oprProduct, sysProductService.selectSysProductById(oprProduct.getProductId()).getCategory());
        if (!equalsAny(oprProduct.getStatus(), ATTACH.getValue(), TOWRAP.getValue())){
            if (getAutoStatus.apply(RobotType.AUTO_PRODUCT_QUALITY.getValue())){
                applicationContext.publishEvent(new QualityEvent(this,companionInfo));
            }else {
                return error("产品状态有误");
            }
        }
        return AjaxResult.success(new AttachmentVO()
                .setCheckProductVo(oprProductMapper.queryCheckProVOById(companionInfo.getPrimaryProductId()))
                .setAttachments(oprAttachmentVOS)
                .setBarcode(companionInfo.getPrimaryProduct().getBarcode())
                .setCompanionBarcode(companionInfo.getCompanionProduct().getBarcode())
                .setAttFrameNo(oprAttachmentVOS.get(0).getFrameNo())
                .setAttNames(oprAttachmentVOS.stream().map(OprAttachmentVO::getAttName).collect(joining(",")))
                .setNum(oprAttachmentVOS.size()));
    }

    /**
     * 附件扫描
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult attachmentScan(String proBarcode, String attBarcode) {
        OprProduct oprProduct = oprProductMapper.queryByBarcode(proBarcode);
        if (oprProduct == null)
            return error("水洗码有误");
        if (!equalsAny(oprProduct.getStatus(), OprProductType.ATTACH.getValue(), OprProductType.TOWRAP.getValue()))
            return error("产品未质检或已包装");

        log.info("附件扫描，proBarcode：[{}]，attBarcode：[{}]", proBarcode, attBarcode);
        CompanionInfo companionInfo = getCompanionVO(oprProduct, sysProductService.selectSysProductById(oprProduct.getProductId()).getCategory());
        OprAttachment oprAttachment = oprAttachmentMapper.queryByBarcodeAndProductId(companionInfo.getPrimaryProductId(), attBarcode);

        if (isNull(oprAttachment))
            return error("该附件不属于此产品");
        OprAttachment attachment = new OprAttachment().setProductId(companionInfo.getPrimaryProductId());

        if (oprAttachment.getIsScan()) {
            if (oprAttachmentMapper.selectOprAttachmentList(attachment)
                    .stream()
                    .map(OprAttachment::getIsScan)
                    .allMatch(TRUE::equals))
                return success("附件已配齐");
            return success("已扫描");
        }
        oprAttachmentMapper.updateOprAttachment(new OprAttachment().setIsScan(true).setId(oprAttachment.getId()));
        //附件已经全部扫描  产品置为待包装状态
        if (oprAttachmentMapper.selectOprAttachmentList(attachment)
                .stream()
                .map(OprAttachment::getIsScan)
                .allMatch(TRUE::equals)) {
            int count = oprProductMapper.updateByProductIdOrCompanionId(new OprProduct().setStatus(TOWRAP.getValue()).setId(companionInfo.getPrimaryProductId()));
            if(count > 0){
                //updateByIdOrCompanionId(new OprProduct().setStatus(OprProductType.TOWRAP.getValue()).setId(companionInfo.getPrimaryProductId()));
                //commonImportRecord(StatusRecordEnum.PRODUCT, companionInfo.getPrimaryProductId(), OprProductType.TOWRAP.getValue(), true);
                commonImportRecord(StatusRecordEnum.PRODUCT,companionInfo.getPrimaryProductId(),OprProductType.TOWRAP.getValue());
                //同一入厂单中所有附件已扫描 释放附件搁架
                if (oprAttachmentMapper.selectOprAttachmentList(new OprAttachment().setFrameNo(oprAttachment.getFrameNo()).setIsScan(false)).isEmpty())
                    sysFrameService.releaseFrame(true, oprAttachment.getFrameNo());
                merchantAsync.backProductState(ProductStatus.builder()
                        .pickupNo(companionInfo.getChPickupNo())
                        .barcode(companionInfo.getPrimaryProduct().getBarcode())
                        .status(OprProductType.TOWRAP.name())
                        .state(0).noWash(false).build(), companionInfo.getChannelId());
            }
            return success("附件已配齐");
        }
        return success("已扫描");
    }


    /**
     * 包装
     * 包装同一个出厂单的第一件衣物时 分配格架
     * 一个出厂单 分配一个格架
     */
    @Override
    //@Transactional(rollbackFor = Exception.class)
    public AjaxResult wrap(String barcode) {
        OprProduct oprProduct = queryByBarcode(barcode);
        if (oprProduct == null)
            return error("无效水洗码");

        if (oprProduct.getShipmentId() == null)
            return error("未下发出厂单");
        log.info("衣物包装，oprProduct：[{}]", toJSONString(oprProduct));
        SysProduct sysProduct = sysProductService.selectSysProductById(oprProduct.getProductId());
        CompanionInfo companionInfo = getCompanionVO(oprProduct, sysProduct.getCategory());
        String frameNo = "";
        if (!equalsAny(oprProduct.getStatus(), TOWRAP.getValue())){
            if (getAutoStatus.apply(RobotType.AUTO_PRODUCT_QUALITY.getValue())){
                applicationContext.publishEvent(new QualityEvent(this,companionInfo));
                if(!oprAttachmentMapper.queryByProductId(oprProduct.getId()).isEmpty()
                        && !getAutoStatus.apply(RobotType.AUTO_PRODUCT_ATTACH.getValue())){
                    return error("衣物需要去配附件");
                }
            }else {
                return error("非待包装状态");
            }
        }
        List<OprProduct> oprProducts = oprProductMapper.queryByShipmentId(oprProduct.getShipmentId());
        OprShipment oprShipment = oprShipmentMapper.selectOprShipmentById(oprProduct.getShipmentId());
        Integer count = 0;
        if (nonNull(oprShipment.getFrameNo())) {
            count = 1;
            frameNo = oprShipment.getFrameNo();
        } else {
            frameNo = sysFrameService.allocateFrame(false);
            log.info("分配衣物搁架，shipmentId：[{}]，frameNo：[{}]",oprShipment.getId(),frameNo);
            count = oprShipmentMapper.updateShipmentFrameNo(new OprShipment().setFrameNo(frameNo).setId(oprShipment.getId()));
            if(count == 0){
                sysFrameService.releaseFrame(false,frameNo);
            }
        }
        String pairBarcode = companionInfo.getPrimaryProduct().getBarcode();
        if (oprProduct.getFrameNo() == null && count > 0) {
                updateByIdOrCompanionId(new OprProduct().setFrameNo(frameNo).setId(companionInfo.getPrimaryProductId()));
                merchantAsync.backProductFrameNo(ProductFrame.builder()
                        .barcode(pairBarcode)
                        .frameNo(frameNo)
                        .build(), oprProduct.getChannelId());
        }
        List<OprAttachment> oprAttachments = oprAttachmentMapper
                .selectOprAttachmentList(new OprAttachment().setProductId(companionInfo.getPrimaryProductId()));

        WrapVO wrapVo = new WrapVO()
                .setOrderNo(oprShipment.getOrderNo())
                .setProductName(sysProduct.getName())
                .setBarcode(pairBarcode)
                .setCompanionBarcode(companionInfo.getCompanionProduct().getBarcode())
                .setFrameNo(frameNo)
                .setCheckTime(ofNullable(getPostRecord(PostRecordEnum.QC, oprProduct.getId())).filter(Objects::nonNull).map(PostRecord::getCreateAt).map(SIMPLE_DATE_FORMAT::format).orElse(""))
                .setPickupTime(ofNullable(getStatusRecord(StatusRecordEnum.PICKUP, oprProduct.getPickupId(), PickupType.RECEIVED.getValue())).filter(Objects::nonNull).map(StatusRecord::getCreateAt).map(SIMPLE_DATE_FORMAT::format).orElse(""))
                .setShipmentNo(nonNull(oprShipment) ? oprShipment.getChShipmentNo() : "")
                .setChannelName(channelService.selectSysChannelById(oprProduct.getChannelId()).getName())
                .setProductNum(oprProducts.stream().map(OprProduct::getCompanionId).filter(Objects::isNull).count())
                .setIsPass(true);

        return success(oprAttachments.size() == 0 ? wrapVo.setAttNum(0) :
                wrapVo.setAttNum(oprAttachments.size())
                        .setAttFrameNo(oprAttachments.get(0).getFrameNo())    //附件格架号
                        .setAttachments(oprAttachments.stream()
                                .mapToLong(OprAttachment::getAttachmentId)
                                .mapToObj(sysAttachmentService::selectSysAttachmentById)
                                .map(SysAttachment::getName)
                                .collect(joining(" "))));
    }

    /**
     * 打包盒子校验
     */
    @Override
    public AjaxResult boxCheck(String boxCode, String barcode) {
        log.info("打包盒子校验，boxCode：[{}]，barcode：[{}]", boxCode, barcode);
        ProductVo productVo = oprProductMapper.selectOprProductByBarcode(OprProduct.builder()
                .barcode(barcode).build());
        if(productVo != null){
            List<SysMaterial> materials = sysMaterialMapper.selectSysMaterialList(SysMaterial.builder().channelId(productVo.getChannelId()).build());
            if(!CollectionUtils.isEmpty(materials)){
                if(boxCode.equals("empty")){
                   return error("盒子码不能为空！");
                }
                boolean b = materials.stream().map(SysMaterial::getBoxCode).anyMatch(m -> m.equals(boxCode));
                if(!b){
                    return error("盒子码格式错误！");
                }
            }
        }
        if(!boxCode.equals("empty")){
            OprMaterial material = oprMaterialMapper.selectOprMaterialByID(productVo.getShipmentId());
            OprMaterial build = OprMaterial.builder()
                    .boxCode(boxCode)
                    .shipmentId(productVo.getShipmentId())
                    .build();
            build.setCreateBy(getUserName());
            build.setModifyBy(getUserName());
            if (material != null) {
                oprMaterialMapper.updateOprMaterial(build);
            } else {
                oprMaterialMapper.insertOprMaterial(build);
            }
        }
        return success();
    }

    /**
     * 打印总检标  status -> PLACED（已包装）
     */
    @Override
    //@Transactional(rollbackFor = Exception.class)
    public AjaxResult printCheckLable(String barcode) {
        OprProduct oprProduct = oprProductMapper.queryByBarcode(barcode);
        if (oprProduct == null)
            return error("水洗码有误");
        if (!oprProduct.getStatus().equals(OprProductType.TOWRAP.getValue()))
            return error("非待包装状态");
        log.info("打印总检标，barcode：[{}]，oprProduct：[{}]", barcode, toJSONString(oprProduct));

        CompanionInfo companionInfo = getCompanionVO(oprProduct, sysProductService.selectSysProductById(oprProduct.getProductId()).getCategory());
        int count = oprProductMapper.updateByProductIdOrCompanionId(new OprProduct().setStatus(WRAPPED.getValue()).setId(companionInfo.getPrimaryProductId()));
        if(count > 0){
            //updateByIdOrCompanionId(new OprProduct().setStatus(OprProductType.WRAPPED.getValue()).setId(companionInfo.getPrimaryProductId()));
            //记录状态
            commonPostRecord(PostRecordEnum.WRAP, companionInfo.getPrimaryProductId());
            //commonImportRecord(StatusRecordEnum.PRODUCT, companionInfo.getPrimaryProductId(), OprProductType.WRAPPED.getValue(), true);
            commonImportRecord(StatusRecordEnum.PRODUCT,companionInfo.getPrimaryProductId(),OprProductType.WRAPPED.getValue());
            merchantAsync.backProductState(ProductStatus.builder()
                    .pickupNo(companionInfo.getChPickupNo())
                    .barcode(companionInfo.getPrimaryProduct().getBarcode())
                    .status(OprProductType.WRAPPED.name())
                    .state(0).noWash(false).build(), companionInfo.getChannelId());

            applicationContext.publishEvent(new PutawayEvent(this, oprProduct.getBarcode())); //触发自动已上架
        }
        return success();
    }

    private CompanionInfo getCompanionVO(OprProduct oprProduct, String category) {
        if (oprProduct == null)
            throw new ResponseException(PRODUCT_INEXISTENCE);
        boolean flag = true;
        OprProduct otherProduct = null;
        if (SHOES.name().equals(category)) {
            if (nonNull(oprProduct.getCompanionId())) {
                otherProduct = oprProductMapper.selectOprProductById(oprProduct.getCompanionId());
                flag = false;
            } else {
                otherProduct = oprProductMapper.queryByCompanionId(oprProduct.getId());
            }
        }
        if (otherProduct == null)
            otherProduct = new OprProduct();
        OprPickup oprPickup = oprPickupMapper.selectOprPickupById(oprProduct.getPickupId());
        CompanionInfo companionInfo = new CompanionInfo(flag ? oprProduct : otherProduct, flag ? otherProduct : oprProduct, flag ? oprProduct.getId() : otherProduct.getId(), oprPickup.getChPickupNo(), oprPickup.getChannelId());

        log.info("查询产品配对信息，companionInfo：[{}]，主产品：[{}]，副产品：[{}]", toJSONString(companionInfo),flag ? toJSONString(oprProduct) : toJSONString(otherProduct), flag ? toJSONString(otherProduct) : toJSONString(oprProduct));
        return companionInfo;
    }

    /**
     * 衣物上架  同一个出厂单全部衣物上架完  请求下物流单
     */
    @Override
    public AjaxResult putaway(String barcode, boolean flag) {
        OprProduct oprProduct = oprProductMapper.queryByBarcodeAndStatus(barcode, OprProductType.WRAPPED.getValue());
        if (oprProduct == null)
            return error("水洗码有误，或衣物非已包装状态");

        log.info("衣物上架，barcode：[{}]，flag：[{}]", barcode, flag);
        CompanionInfo companionInfo = getCompanionVO(oprProduct, sysProductService.selectSysProductById(oprProduct.getProductId()).getCategory());

        updateByIdOrCompanionId(new OprProduct().setStatus(OprProductType.PLACED.getValue()).setId(companionInfo.getPrimaryProductId()));
        commonImportRecord(StatusRecordEnum.PRODUCT, companionInfo.getPrimaryProductId(), OprProductType.PLACED.getValue());
        merchantAsync.backProductState(ProductStatus.builder()
                .pickupNo(companionInfo.getChPickupNo())
                .barcode(companionInfo.getPrimaryProduct().getBarcode())
                .status(OprProductType.PLACED.name())
                .state(0).noWash(false).build(), companionInfo.getChannelId());
        //全部已上架  出厂单状态 -> 物流下单
        if (oprProductMapper.queryByShipmentId(oprProduct.getShipmentId()).stream().map(OprProduct::getStatus).allMatch(OprProductType.PLACED.getValue()::equals)) {
            oprShipmentMapper.updateOprShipment(new OprShipment().setStatus(ShipMentType.ORDERING.getValue()).setId(oprProduct.getShipmentId()));
            commonImportRecord(StatusRecordEnum.SHIPMENT, oprProduct.getShipmentId(), ShipMentType.ORDERING.getValue());
            //回写出厂单状态
            merchantAsync.backShipState(ShipmentStatus.builder().shipmentNo(oprShipmentMapper.selectOprShipmentById(oprProduct.getShipmentId()).getChShipmentNo()).status(ShipMentType.ORDERING.name()).build(), companionInfo.getChannelId());
        }
        return success("已上架");
    }

    @Override
    public AjaxResult clothes(String status, PackageQueryPara para) {
        log.info("打包衣物列表，status：[{}]，para：[{}}",status,toJSONString(para));
        int count = selectCountByBarcodeAndStatus(status, para);
        if (count == 0)
            return success(new ArrayList()).put("total", 0);

        ArrayList<ProductItemVO> productItemVOS = new ArrayList<>();
        selectByBarcodeAndStatus(status, para).forEach(oprProduct -> {
            OprShipment oprShipment = oprShipmentMapper.selectOprShipmentById(oprProduct.getShipmentId());
            if (oprShipment == null) {
                log.error("出厂单id有误，barcode：[{}]，shipmentId：[{}]", oprProduct.getBarcode(), oprProduct.getShipmentId());
                throw new ResponseException(SHIPMENT_ID_ERROR);
            }
            ProductItemVO productItemVO = new ProductItemVO()
                    .setProductId(oprProduct.getId())
                    .setBarcode(overlay(oprProduct.getBarcode(), "*****", 4, 9))
                    .setWholeBarcode(oprProduct.getBarcode())
                    .setFrameNo(oprProduct.getFrameNo())
                    .setStatus(getName(oprProduct.getStatus()))
                    .setIsScan(equalsAny(oprProduct.getStatus(), OprProductType.PACKED.getValue(), OprProductType.SHIPPED.getValue()) ? "是" : "否")
                    .setAttaNames(oprAttachmentMapper.selectByProductId(oprProduct.getId()).stream().map(AttachmentInfo::getAttName).collect(joining("，")))
                    .setIsQualified((oprProduct.getFlag() & 256) == 256 ? "污渍终止" : "合格")
                    .setOrderNo(oprShipment.getOrderNo())
                    .setShipmentId(oprShipment.getId())
                    .setShipmentNO(oprShipment.getChShipmentNo())
                    .setTypeName(sysProductService.selectSysProductById(oprProduct.getProductId()).getName());
            productItemVOS.add(productItemVO);
        });
        log.info("打包衣物列表，total：[{}]，productItemVOS：[{}]",count,toJSONString(productItemVOS));
        return success(productItemVOS).put("total", count);
    }

    @Override
    public AjaxResult shipments(String status, PackageQueryPara para) {
        log.info("打包出厂单列表，status：[{}]，para：[{}}",status,toJSONString(para));
        ArrayList<ShipmentItemVO> shipmentItemVOS = new ArrayList<>();
        List<ShipmentItem> shipmentItems = oprShipmentMapper.shipmentsByNoAndHour(status, para);
        Integer total = getTotal(shipmentItems.size(), para);
        if (total == -1) {
            para.setPageNum(para.getPageNum() - 1);
            total = para.getPageNum() * para.getPageSize();
            shipmentItems = oprShipmentMapper.shipmentsByNoAndHour(status, para);
        }
        shipmentItems.forEach(shipment -> {
            OprMaterial oprMaterial = oprMaterialMapper.selectOprMaterialByID(shipment.getId());
            List<OprSysProduct> oprSysProducts = oprSysProductByShipmentId(shipment.getId());
            HashMap<String, List<OprSysProduct>> categoryMap = new HashMap<>();
            oprSysProducts.forEach(product -> {
                categoryMap.computeIfAbsent(product.getCategory(),key -> new ArrayList<>()).add(product);
            });
            ShipmentItemVO shipmentItemVO = new ShipmentItemVO()
                    .setShipmentId(shipment.getId())
                    .setShipmentNo(shipment.getChShipmentNo())
                    .setClothesNum(categoryMap.get(CLOTHES.name()) != null ? categoryMap.get(CLOTHES.name()).size() : 0)
                    .setShoesNum(categoryMap.get(CategoryType.SHOES.name()) != null ? categoryMap.get(SHOES.name()).size() : 0)
                    .setAttaNum(oprSysProducts.stream().map(OprSysProduct::getId).map(oprAttachmentMapper::countOprAttVoByProId).reduce(0, (a, b) -> a + b))
                    .setTotalNum(oprSysProducts.size())
                    .setOrderNo(shipment.getOrderNo())
                    .setBoxCode(oprMaterial != null ? oprMaterial.getBoxCode() : "")
                    .setCarrier(shipment.getCarrier())
                    .setExpressNo(shipment.getExpressNo())
                    .setStatus(shipment.getStatus())
                    .setHour(shipment.getHour());
            shipmentItemVOS.add(shipmentItemVO);
        });
        return success(shipmentItemVOS).put("total", total);
    }

    /**
     * 打包详情
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PackageDetailVO packageDetail(Long shipmentId) {
        log.info("打包详情，shipmentId：[{}]",shipmentId);

        OprShipment oprShipment = oprShipmentMapper.selectOprShipmentById(shipmentId);
        if (!equalsAny(oprShipment.getStatus(), ShipMentType.PICKED.getValue(), ShipMentType.PACKING.getValue(), ShipMentType.PACKED.getValue()))
            throw new ResponseException(NO_PICKED_OR_SHIPPED);

        if (ShipMentType.PICKED.getValue().equals(oprShipment.getStatus())) {
            if (oprShipmentMapper.updateOprShipment(oprShipment.setStatus(ShipMentType.PACKING.getValue())) == 0)
                throw new ResponseException(STATUS_UPDATE_ERROR);
            commonImportRecord(StatusRecordEnum.SHIPMENT, oprShipment.getId(), ShipMentType.PACKING.getValue());
            merchantAsync.backShipState(ShipmentStatus.builder().shipmentNo(oprShipment.getChShipmentNo()).status(ShipMentType.PACKING.name()).build(), oprShipment.getChannelId());
        }
        List<OprProduct> oprProducts = oprProductMapper.queryByShipmentIdExcludeCompanion(oprShipment.getId());
        PackageDetailVO packageDetailVO = new PackageDetailVO()
                .setChannelId(oprShipment.getChannelId())
                .setClothesNum(oprProducts.size())
                .setShipmentId(oprShipment.getId())
                .setExpressNo(oprShipment.getExpressNo())
                .setShipmentNO(oprShipment.getChShipmentNo());

        AtomicInteger num = new AtomicInteger();
        List<ProductItemVO> items = new ArrayList<>();

        oprProducts.forEach(oprProduct -> {
            List<OprAttachment> oprAttachments = oprAttachmentMapper.selectOprAttachmentList(new OprAttachment().setProductId(oprProduct.getId()));
            ProductItemVO packageItemVo = new ProductItemVO()
                    .setShipmentId(oprShipment.getId())
                    .setShipmentNO(oprShipment.getChShipmentNo())
                    .setProductId(oprProduct.getId())
                    .setBarcode(overlay(oprProduct.getBarcode(), "*****", 4, 9))
                    .setWholeBarcode(oprProduct.getBarcode())
                    .setFrameNo(oprProduct.getFrameNo())
                    .setOrderNo(oprShipment.getOrderNo())
                    .setTypeName(sysProductService.selectSysProductById(oprProduct.getProductId()).getName())
                    .setIsScan(equalsAny(oprProduct.getStatus(), OprProductType.PACKED.getValue(), OprProductType.SHIPPED.getValue()) ? "是" : "否")                                       //待确认
                    .setStatus(OprProductType.getName(oprProduct.getStatus()))                                     //待确认
                    .setIsQualified((oprProduct.getFlag() & 256) == 256 ? "污渍终止" : "合格");                              //待确认

            packageItemVo.setAttaNames(oprAttachments.size() > 0 ?
                    oprAttachments.stream()
                            .mapToLong(OprAttachment::getAttachmentId)
                            .mapToObj(sysAttachmentService::selectSysAttachmentById)
                            .map(SysAttachment::getName)
                            .collect(joining(",")) : "");
            num.addAndGet(oprAttachments.size());

            items.add(packageItemVo);
        });
        return packageDetailVO.setAttaNum(num.get()).setItems(items);
    }

    @Override
    public AjaxResult packageDetail(String barcode) {
        OprProduct oprProduct = oprProductMapper.queryByBarcode(barcode);
        if (oprProduct == null)
            return error("无效水洗码");

        OprShipment oprShipment = oprShipmentMapper.selectOprShipmentById(oprProduct.getShipmentId());
        if (oprShipment == null)
            return error("出厂单不存在");
        if(Integer.parseInt(oprShipment.getStatus()) < 4){
            return error("未打印拣货单");
        }
        Boolean leave = merchantAsync.isLeave(oprShipment.getOrderNo(), oprShipment.getChannelId());
        if(!leave){
            return error("订单有未完结的补款工单或者未到出厂时间");
        }
        applicationContext.publishEvent(new PackageEvent(this, oprShipment.getId())); //触发自动装箱事件
        AjaxResult ajaxResult = AjaxResult.success(this.packageDetail(oprShipment.getId()));
        if (oprProductMapper.selectProductByShipmentId(oprShipment.getId()).stream().map(OprProduct::getStatus).allMatch(OprProductType.PACKED.getValue()::equals)) {
            log.info("返回面单信息，shipmentNo：[{}]，label：[{}]",oprShipment.getChShipmentNo(),oprShipment.getLabel());
            ajaxResult.put("label", oprShipment.getLabel());
        }
        return ajaxResult;
    }

    /**
     * 产品打包扫描
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult packageScan(String barcode) {
        OprProduct oprProduct = oprProductMapper.queryByBarcode(barcode);
        if (oprProduct == null)
            return warn("水洗码有误");
        OprShipment oprShipment = oprShipmentMapper.selectOprShipmentById(oprProduct.getShipmentId());
        if (oprShipment == null)
            return error("出厂单不存在！");
        if(!oprProduct.getStatus().equals(OprProductType.PICKED.getValue())){
            applicationContext.publishEvent(new TopickEvent(this, oprProduct.getShipmentId())); //触发打包开始事件
        }
        log.info("产品打包扫描，barcode：[{}]，oprProduct：[{}]", barcode, toJSONString(oprProduct));
        int count = updateByIdOrCompanionId(new OprProduct().setStatus(PACKED.getValue()).setId(oprProduct.getId()));
        if(count > 0){
            commonPostRecord(PostRecordEnum.PACK, oprProduct.getId());
            commonImportRecord(StatusRecordEnum.PRODUCT, oprProduct.getId(), OprProductType.PACKED.getValue());
            OprPickup oprPickup = oprPickupMapper.selectOprPickupById(oprProduct.getPickupId());
            merchantAsync.backProductState(ProductStatus.builder()
                    .pickupNo(oprPickup.getChPickupNo())
                    .barcode(oprProduct.getBarcode())
                    .status(OprProductType.PACKED.name())
                    .state(0).noWash(false).build(), oprPickup.getChannelId());
        }
        return success();
    }

    /**
     * 面单扫描
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult labelScan(String expressNo) {
        log.info("面单扫描，expressNo：[{}]", expressNo);
        OprShipment oprShipment = oprShipmentMapper.queryByExpressNoAndStatus(expressNo, ShipMentType.PACKING.getValue());
        if (oprShipment == null)
            return error("运单号或出厂单状态有误");
        if (isBlank(oprShipment.getFrameNo()))
            return error("搁架号不存在");

        List<OprProduct> oprProducts = oprProductMapper.queryByShipmentId(oprShipment.getId());
        if (!oprProducts.stream().map(OprProduct::getStatus).allMatch(OprProductType.PACKED.getValue()::equals))
            return error("该出厂单存在未打包衣物");

        if (oprShipmentMapper.updateOprShipment(new OprShipment().setStatus(ShipMentType.PACKED.getValue()).setId(oprShipment.getId())) == 0)
            throw new ResponseException(STATUS_UPDATE_ERROR);
        commonImportRecord(StatusRecordEnum.SHIPMENT, oprShipment.getId(), ShipMentType.PACKED.getValue());

        if (oprProductMapper.releasableFrame(oprShipment.getFrameNo()).isEmpty())
            sysFrameService.releaseFrame(false, oprShipment.getFrameNo());
        merchantAsync.backShipState(ShipmentStatus.builder().shipmentNo(oprShipment.getChShipmentNo()).status(ShipMentType.PACKED.name()).build(), oprShipment.getChannelId());

        //applicationContext.publishEvent(new OutFactoryEvent(this, oprShipment.getExpressNo())); //触发自动出厂事件
        return success();
    }

    /**
     * 出厂
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult outFactory(String expressNo) {
        log.info("衣物出厂，expressNo：[{}]", expressNo);
        OprShipment oprShipment = oprShipmentMapper.queryByExpressNo(expressNo);
        if(oprShipment == null)
            return error("运单号有误");
        if (!equalsAny(oprShipment.getStatus(), ShipMentType.PACKING.getValue(), ShipMentType.PACKED.getValue()))
            return warn("状态有误");

        if(oprShipment.getStatus().equals(ShipMentType.PACKING.getValue())){
            log.info("手动出厂-跳过运单扫描，出厂单号：[{}]",oprShipment.getChShipmentNo());
            /*List<OprProduct> products = oprProductMapper.queryByShipmentId(oprShipment.getId());
            long count = products.stream()
                    .map(OprProduct::getStatus)
                    .filter(status -> !OprProductType.PACKED.getValue().equals(status))
                    .count();
            if(count != 0){
                return error("有未打包的衣物");
            }
            oprShipment.setStatus(ShipMentType.PACKED.getValue());
            oprShipmentMapper.updateOprShipment(oprShipment);
            commonImportRecord(StatusRecordEnum.SHIPMENT, oprShipment.getId(), ShipMentType.PACKED.getValue());
            merchantAsync.backShipState(ShipmentStatus.builder().shipmentNo(oprShipment.getChShipmentNo()).status(ShipMentType.PACKED.name()).build(), oprShipment.getChannelId());

            sysFrameService.releaseFrame(false, oprShipment.getFrameNo());*/
            AjaxResult result = labelScan(expressNo);
            if(result.get("code").equals(HttpStatus.ERROR)){
                return result;
            }
        }
        selectByShipmentId(oprShipment.getId())
                .forEach(oprProduct -> {
                    updateByIdOrCompanionId(new OprProduct().setStatus(OprProductType.SHIPPED.getValue()).setId(oprProduct.getId()));
                    commonImportRecord(StatusRecordEnum.PRODUCT, oprProduct.getId(), OprProductType.SHIPPED.getValue());
                    //回写产品状态
                    OprPickup oprPickup = oprPickupMapper.selectOprPickupById(oprProduct.getPickupId());
                    if(oprProduct.getCompanionId() == null){
                        merchantAsync.backProductState(ProductStatus.builder()
                                .pickupNo(oprPickup.getChPickupNo())
                                .barcode(oprProduct.getBarcode())
                                .status(OprProductType.SHIPPED.name())
                                .state(0).noWash(false).build(), oprPickup.getChannelId());
                    }
                });
        if (oprShipmentMapper.updateOprShipment(new OprShipment().setStatus(ShipMentType.SHIPPED.getValue()).setId(oprShipment.getId())) == 0)
            throw new ResponseException(STATUS_UPDATE_ERROR);
        commonImportRecord(StatusRecordEnum.SHIPMENT, oprShipment.getId(), ShipMentType.SHIPPED.getValue());
        merchantAsync.backShipState(ShipmentStatus.builder().shipmentNo(oprShipment.getChShipmentNo()).status(ShipMentType.SHIPPED.name()).build(), oprShipment.getChannelId());
        return success();
    }

    @Override
    public int updateStatueByBarcode(String barcode, String status) {
        OprProduct product = oprProductMapper.queryByBarcode(barcode);
        OprProduct build = OprProduct.builder().barcode(barcode).status(status).build();
        int num = 0;
        if (product != null) {
            build.setId(product.getId());
            num = oprProductMapper.updateStatueById(build);
        }
        return num;
    }

    @Override
    public OprProduct queryByBarcode(String barcode) {
        return oprProductMapper.queryByBarcode(barcode);
    }

    @Override
    public OprProduct selectNoQCByBarcode(String barcode) {
        return oprProductMapper.selectNoQCByBarcode(barcode);
    }

    @Override
    public OprProduct queryProductById(Long optProductId) {
        return oprProductMapper.selectOprProductById(optProductId);
    }

    @Override
    public List<OprProduct> selectByPickupId(Long pickupId) {
        return oprProductMapper.queryByPickupId(pickupId);
    }

    @Override
    public List<OprProduct> selectProductByShipmentId(Long id) {
        return oprProductMapper.queryByShipmentId(id);
    }

    @Override
    public List<OprProduct> selectByShipmentId(Long shipmentId) {
        return oprProductMapper.queryByShipmentId(shipmentId);
    }

    @Override
    public List<OprProduct> selectByShipmentIdExcludeCompanion(Long shipmentId) {
        return oprProductMapper.queryByShipmentIdExcludeCompanion(shipmentId);
    }

    /**
     * 查询作业产品
     *
     * @param id 作业产品主键
     * @return 作业产品
     */
    @Override
    public OprProduct selectOprProductById(Long id) {
        return oprProductMapper.selectOprProductById(id);
    }

    /**
     * 查询作业产品列表
     *
     * @param oprProduct 作业产品
     * @return 作业产品
     */
    @Override
    public List<OprProduct> selectOprProductList(OprProduct oprProduct) {
        return oprProductMapper.selectOprProductList(oprProduct);
    }

    /**
     * 新增作业产品
     *
     * @param oprProduct 作业产品
     * @return 结果
     */
    @Override
    public int insertOprProduct(OprProduct oprProduct) {
        return oprProductMapper.insertOprProduct(oprProduct);
    }


    /**
     * 修改作业产品
     *
     * @param oprProduct 作业产品
     * @return 结果
     */
    @Override
    public int updateOprProduct(OprProduct oprProduct) {
        int flag = oprProductMapper.updateOprProduct(oprProduct);
        if (flag == 0)
            throw new ResponseException(UPDATE_ERROR);
        return flag;
    }

    /**
     * 根据产品id或companionId修改作业产品
     */
    @Override
    public int updateByIdOrCompanionId(OprProduct oprProduct) {
        log.info("updateByIdOrCompanionId...oprProduct: [{}]", toJSONString(oprProduct));
        return oprProductMapper.updateByIdOrCompanionId(oprProduct);
    }

    /**
     * 根据产品id或companionId修改作业产品
     */
    @Override
    public int updateByCompanionId(OprProduct oprProduct) {
        log.info("updateByCompanionId...oprProduct: [{}]", toJSONString(oprProduct));
        return oprProductMapper.updateByCompanionId(oprProduct);
    }


    /**
     * 批量删除作业产品
     *
     * @param ids 需要删除的作业产品主键
     * @return 结果
     */
    @Override
    public int deleteOprProductByIds(String ids) {
        return 0;
        //oprProductMapper.deleteOprProductByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除作业产品信息
     *
     * @param id 作业产品主键
     * @return 结果
     */
    @Override
    public int deleteOprProductById(Long id) {
        return oprProductMapper.deleteOprProductById(id);
    }

    /**
     * 衣物核查--查询商品列表
     *
     * @param expressNo
     */
    @Override
    public AjaxResult getProductList(String expressNo) {
        log.info("打印衣物核查--查询商品列表请求参数--方法::getProductList------param:[{}]", expressNo);
        applicationContext.publishEvent(new CheckEvent(this, expressNo)); //触发准备核查事件
        PickupVo pickupVo = oprPickupMapper.selectPickupByExpressNo(expressNo);
        if (pickupVo == null) {
            return error("找不到入场单信息");
        }
        if (!equalsAny(pickupVo.getStatus(), PickupType.SIGNFOFF.getValue(), PickupType.VERIFY.getValue()))
            return error("入场单状态错误");
        pickupVo.setPickupType(stream(WorkType.explode(pickupVo.getFlag())).toList().stream().map(WorkType::name).collect(Collectors.toList()));
        List<OprPickup> pickups = oprPickupMapper.selectOprPickupList(OprPickup.builder().channelId(pickupVo.getChannelId()).orderNo(pickupVo.getOrderNo()).build());
        pickupVo.setPickupNum(pickups.size());
        OprPickup pickup = OprPickup.builder().status(PickupType.VERIFY.getValue()).expressNo(pickupVo.getExpressNo()).build();
        pickup.setId(pickupVo.getId());
        SysChannel channel = channelService.selectSysChannelById(pickupVo.getChannelId());
        if(channel != null){
            pickupVo.setChannelName(channel.getName());
            pickupVo.setChannelCode(channel.getCode());
        }
        if (pickupVo.getStatus().equals(PickupType.SIGNFOFF.getValue())) {
            oprPickupMapper.updatePickupStatus(pickup);
            //保存入场单状态核查中改变记录
            commonImportRecord(StatusRecordEnum.PICKUP, pickup.getId(), pickup.getStatus());
            //给渠道回写入场单核查中状态
            merchantAsync.backPickState(PickUpStatus.builder()
                    .pickupNo(pickupVo.getChPickupNo())
                    .status(PickupType.instance(pickup.getStatus()).toString())
                    .build(), pickupVo.getChannelId());
        }
        List<ProductVo> productVos = new ArrayList<>();
        if (pickupVo.getId() != null) {
            List<OprMerchandise> list = oprMerchandiseMapper.selectMerListByPicId(pickupVo.getId());
            list.forEach(oprMerchandise -> {
                ProductVo productVo = oprProductMapper.selectProductVoInfo(oprMerchandise.getId());
                if (productVo == null) {
                    productVo = ProductVo.builder().merchandiseId(oprMerchandise.getId()).name(oprMerchandise.getName()).build();
                } else {
                    OprProduct product = oprProductMapper.selectOprProductByCompanionId(productVo.getId());
                    if (product != null) {
                        productVo.setPairBarcode(product.getBarcode());
                    }
                    Integer flag = productVo.getFlag();
                    productVo.setBrandList(stream(MaterialType.values()).filter(s -> s.in(flag)).map(MaterialType::value).collect(Collectors.toList()));
                    productVo.setImgList(oprProductImgMapper.selectOprProductImgList(OprProductImg.builder().oprProductId(productVo.getId()).imgType("4").build()));
                }
                productVo.setCode(oprMerchandise.getCode());
                productVos.add(productVo);
            });
            pickupVo.setProductVoList(productVos);
            String result = null;
            try {
                result = merchantAsync.getOrderInfo(pickupVo.getOrderNo(),pickupVo.getChannelId());
            } catch (Exception e) {
                log.info("channel---getOrderInfo  error:[{}]", e);
            }
            if (StringUtils.isNotBlank(result)) {
                JSONObject jsonObject = parseObject(result);
                pickupVo.setUserComment(jsonObject.getString("comment"));
                pickupVo.setMerchantComment(jsonObject.getString("summary"));
            }
        }
        return success(pickupVo);
    }

    /**
     * 衣物核查--查询附件列表
     *
     * @param
     */
    @Override
    public List<OprAttachment> getAttachmentList(Long oprProductId) {
        return oprAttachmentMapper.selectAttachmentList(oprProductId);
    }

    /**
     * 衣物核查--查询产品图片列表
     *
     * @param
     */
    @Override
    public List<OprProductImg> getOprProductImgList(Long oprProductId, String imgType) {
        List<OprProductImg> imgs = oprProductImgMapper.selectOprProductImgList(OprProductImg.builder().oprProductId(oprProductId).imgType(imgType).build());
        imgs.stream().filter(oprProductImg -> StringUtils.equalsAny(oprProductImg.getImgType(),"1","5"))
                .forEach(oprProductImg -> oprProductImg.setOprDefeimgList(oprDefeimgMapper.selectDefeByImgId(oprProductImg.getId())));
        return imgs;
    }


    /**
     * 衣物核查--添加作业产品信息
     *
     * @param productVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @RepeatSubmit
    public AjaxResult addOprProduct(ProductVo productVo) {
        log.info("打印衣物核查--添加作业产品信息请求参数--方法::addOprProduct------param:[{}]", productVo.toString());
        ProductAddVo vo = ProductAddVo.builder().build();
        productVo.setStatus(OprProductType.VERIFY.getValue());
        productVo.setCreateBy(getUserName());
        productVo.setModifyBy(getUserName());
        String config = channelService.selectConfigById(productVo.getChannelId());
        if (StringUtils.isEmpty(config) || !config.contains("barcode")) {
            return error("水洗码生成错误");
        }
        String code = parseObject(config).getString("barcode");
        SysProduct sysProduct = sysProductService.selectSysProductById(productVo.getProductId());
        ProductVo build = ProductVo.builder().build();
        OprPickup pickup = oprPickupMapper.selectOprPickupById(productVo.getPickupId());
        if(pickup == null){
            return AjaxResult.error("入场单信息错误");
        }
        if(pickup.getStatus().equals(PickupType.RECEIVED.getValue())){
            return AjaxResult.error("入场单已入厂");
        }
        build.setFlag(pickup.getFlag());
        productVo.setFlag(pickup.getFlag());
        if (productVo.getId() == null) {
            OprProduct product = oprProductMapper.selectOprProductByMerchandiseId(productVo.getMerchandiseId());
            if(product != null){
                 return AjaxResult.error("商品ID已存在，请刷新页面");
            }
            productVo.setBarcode(barcodeGenerator.generator(code));
            oprProductMapper.insertProductVo(productVo);
            if (sysProduct.getCategory().equals("SHOES")) {
                BeanUtils.copyBeanProp(build, productVo);
                build.setId(null);
                build.setBarcode(barcodeGenerator.generator(code));
                build.setCompanionId(productVo.getId());
                oprProductMapper.insertProductVo(build);
                vo.setPairBarcode(build.getBarcode());
            }
            vo.setId(productVo.getId());
            vo.setBarcode(productVo.getBarcode());
        } else {
            oprProductMapper.updateProductVo(productVo);
            OprProduct product = oprProductMapper.selectOprProductByCompanionId(productVo.getId());
            if (sysProduct.getCategory().equals("SHOES")) {
                if (product == null) {
                    BeanUtils.copyBeanProp(build, productVo);
                    build.setId(null);
                    build.setBarcode(barcodeGenerator.generator(code));
                    build.setCompanionId(productVo.getId());
                    oprProductMapper.insertProductVo(build);
                    vo.setPairBarcode(build.getBarcode());
                } else {
                    ProductVo builder = ProductVo.builder().productId(productVo.getProductId()).build();
                    builder.setId(product.getId());
                    oprProductMapper.updateProductVo(builder);
                    vo.setPairBarcode(product.getBarcode());
                }
            } else {
                if (product != null) {
                    ProductVo builder = ProductVo.builder().build();
                    builder.setId(product.getId());
                    builder.setFlag(FlagType.DELETE.value());
                    oprProductMapper.updateProductVo(builder);
                }
            }
            vo.setId(productVo.getId());
            vo.setBarcode(productVo.getBarcode());
        }
        commonImportRecord(StatusRecordEnum.PRODUCT, productVo.getId(),
                productVo.getStatus());
        return success(vo);
    }

    @Override
    public AjaxResult addMerchandise(OprMerchandise oprMerchandise) {
        oprMerchandise.setCreateBy(getUserName());
        oprMerchandise.setModifyBy(getUserName());
        oprMerchandiseMapper.insertOprMerchandise(oprMerchandise);
        return success(oprMerchandise.getId());
    }


    /**
     * 衣物核查--添加作业产品衣物类型
     *
     * @param flag id
     */
    @Override
    public int addProductType(Integer flag, Long id) {
        OprProduct oprProduct = new OprProduct();
        oprProduct.setId(id);
        oprProduct.setFlag(flag);
        return oprProductMapper.updateOprProduct(oprProduct);
    }

    /**
     * 衣物核查--删除作业产品衣物类型
     *
     * @param flag id
     */
    @Override
    public int deleteProductType(Integer flag, Long id) {
        OprProduct oprProduct = new OprProduct();
        oprProduct.setId(id);
        oprProduct.setFlag(flag);
        return oprProductMapper.deleteFlagByIds(oprProduct);
    }


    /**
     * 衣物核查--添加作业产品图片信息
     *
     * @param productImg
     */
    @Override
    public AjaxResult addImg(OprProductImg productImg) {
        productImg.setCreateBy(getUserName());
        productImg.setModifyBy(getUserName());
        oprProductImgMapper.insertOprProductImg(productImg);
        return success(productImg.getId());
    }

    @Override
    public AjaxResult addImgDesc(Long imgId, String remark) {
        OprProductImg img = OprProductImg.builder().remark(remark).build();
        img.setId(imgId);
        return success(oprProductImgMapper.updateOprProductImg(img));
    }

    /**
     * 衣物核查--添加图片瑕疵信息
     *
     * @param oprDefeimg
     */
    @Override
    public AjaxResult addDefeImg(OprDefeimg oprDefeimg) {
        oprDefeimg.setCreateBy(getUserName());
        oprDefeimg.setModifyBy(getUserName());
        if (oprDefeimg.getId() != null) {
            oprDefeimgMapper.updateOprDefeimg(oprDefeimg);
        } else {
            oprDefeimgMapper.insertOprDefeimg(oprDefeimg);
        }
        return success(oprDefeimg.getId());
    }

    /**
     * 衣物核查--删除作业产品图片
     *
     * @param imgId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delImg(Long imgId) {
        OprProductImg productImg = new OprProductImg();
        productImg.setId(imgId);
        productImg.setFlag(FlagType.DELETE.value());
        int num = oprProductImgMapper.updateOprProductImg(productImg);
        if (num > 0) {
            OprDefeimg defeimg = OprDefeimg.builder().imgId(imgId).build();
            defeimg.setFlag(FlagType.DELETE.value());
            oprDefeimgMapper.updateOprDefeimgByimgId(defeimg);
        }
        return num;
    }

    /**
     * 衣物核查--删除瑕疵图片
     *
     * @param id
     */
    @Override
    public int delDefeImg(Long id) {
        OprDefeimg defeimg = OprDefeimg.builder().build();
        defeimg.setId(id);
        defeimg.setFlag(FlagType.DELETE.value());
        return oprDefeimgMapper.updateOprDefeimg(defeimg);
    }

    /**
     * 衣物核查--入厂核查
     *
     * @param oprProductIds
     * @param pickId
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public AjaxResult check(Long[] oprProductIds, Long pickId) {
        log.info("打印衣物核查--入厂核查请求参数--方法::check------oprProductIds:[{}],pickId:[{}]",Arrays.toString(oprProductIds), pickId);
        OprPickup oprPickup = new OprPickup();
        OprPickup pickup = oprPickupMapper.selectOprPickupById(pickId);
        if(pickup == null){
            return AjaxResult.error("入场单信息错误");
        }
        if(pickup.getStatus().equals(PickupType.RECEIVED.getValue())){
             return AjaxResult.error("入场单已入厂");
        }
        AtomicInteger num = new AtomicInteger();
        if (oprProductIds != null) {
            List<Long> longs = Arrays.asList(oprProductIds);
            longs.forEach(id -> {
                List<OprProductImg> imgList = oprProductImgMapper.selectOprProductImgList(OprProductImg.builder().oprProductId(id).imgType("1").build());
                if (imgList.isEmpty()) {
                    throw new ResponseException("衣物至少需要拍摄一张图片");
                }
                OprProduct oprProduct = oprProductMapper.selectOprProductById(id);
                if(oprProduct == null){
                    throw new ResponseException("产品信息错误");
                }
                OprProduct product = oprProductMapper.selectOprProductByCompanionId(id);
                if (product != null) {
                    product.setStatus(OprProductType.TOWASH.getValue());
                    oprProductMapper.updateOprProduct(product);
                }
                oprProduct.setId(id);
                oprProduct.setStatus(OprProductType.TOWASH.getValue());
                int productCount = oprProductMapper.updateProductTowash(oprProduct);
                if(productCount > 0){
                    //保存产品状态待洗涤改变记录
                    commonImportRecord(StatusRecordEnum.PRODUCT,
                            id, oprProduct.getStatus());
                    //保存入厂核查的操作记录
                    commonPostRecord(PostRecordEnum.VERIFY, id);
                    //给渠道回写产品具体信息
                    SysProduct sysProduct = sysProductService.selectSysProductById(oprProduct.getProductId());
                    List<OprProductImg> imgs = oprProductImgMapper.selectImgByoprId(oprProduct.getId());
                    List<RiskVo> riskVos = new ArrayList<>();
                    AtomicReference<Boolean> risk = new AtomicReference<>(false);
                    imgs.forEach(i -> {
                        if (StringUtils.isNotBlank(i.getRemark())) {
                            risk.set(true);
                            riskVos.add(RiskVo.builder().img(i.getImgUrl()).remark(i.getRemark()).build());
                        }
                        i.setOprDefeimgList(oprDefeimgMapper.selectDefeByImgId(i.getId()));
                    });
                    String result = merchantAsync.backProduct(OprProductInfo.builder()
                            .pickupNo(pickup.getChPickupNo())
                            .barcode(oprProduct.getBarcode())
                            .code(sysProduct.getCode())
                            .name(sysProduct.getName())
                            .number(longs.size())
                            .flaws(oprDefeimgMapper.selectDefeByProductId(oprProduct.getId()).stream().map(OprDefeimg::getName).collect(joining(",")))
                            .imgList(imgs.stream().map(OprProductImg::getImgUrl).collect(Collectors.toList()))
                            .oprAttachments(oprAttachmentMapper.selectByProductId(oprProduct.getId()))
                            .status(OprProductType.instance(oprProduct.getStatus()).toString())
                            .typeList(stream(MaterialType.values()).filter(s -> s.in(oprProduct.getFlag())).collect(Collectors.toList()))
                            .risk(risk.get())
                            .flawImg(imgs)
                            .riskList(riskVos)
                            .build(), oprProduct.getChannelId());
                    if (!result.equals("201")) {
                        num.getAndIncrement();
                    }
                }
//                //给渠道回写产品待洗涤状态
//                merchantAsync.backProductState(ProductStatus.builder()
//                        .pickupNo(pickup.getChPickupNo())
//                        .barcode(oprProductMapper.selectOprProductById(id).getBarcode())
//                        .status(OprProductType.instance(oprProduct.getStatus()).toString())
//                        .build(),pickup.getChannelId());
            });
        }
        if (num.get() != 0) {
            throw new ResponseException("渠道信息同步失败，请重试!");
        }
        oprPickup.setId(pickId);
        oprPickup.setStatus(PickupType.RECEIVED.getValue());
        int updateCount = oprPickupMapper.updatePickupReceived(oprPickup);
        if(updateCount > 0){
            //保存入场单已入场状态改变记录
            commonImportRecord(StatusRecordEnum.PICKUP, pickId,
                    oprPickup.getStatus());
            //给渠道回写入场单已入场状态
            String code = merchantAsync.backPickState(PickUpStatus.builder()
                    .pickupNo(pickup.getChPickupNo())
                    .status(PickupType.instance(oprPickup.getStatus()).toString())
                    .build(), pickup.getChannelId());
            log.info("channel---backPickState---return  pickupNo[{}],code:[{}]",pickup.getChPickupNo(),code);
            if (!equalsAny(code, "201", "207")) {
                throw new ResponseException("渠道信息同步失败，请重试!");
            }
            if (code.equals("207")) {
                return success("衣物入厂有生成工单，请把问题衣物先送至客服部");
            /*String str = updatePickupFlag(pickId, true, FlagType.HOLDING.value());
            if (!str.equals("success")) {
                throw new RuntimeException(str);

            }*/
            }
        }
        //入厂核查保存时触发工单校验
        //applicationContext.publishEvent(new CheckTicketEvent(this,pickId));
        return success();
    }


    /**
     * 质检---查询产品详情
     *
     * @param barcode
     */
    @Override
    public AjaxResult getProductByBarcode(String barcode) {
        log.info("打印质检---查询产品详情请求参数--方法::getProductByBarcode------param:[{}]", barcode);
        applicationContext.publishEvent(new ToinspectEvent(this, barcode)); //质检时触发后处理事件
        ProductVo productVo = oprProductMapper.selectOprProductByBarcode(OprProduct.builder().barcode(barcode).build());
        if (productVo == null) {
            return warn(barcode.concat(" 找不到产品信息"));
        }
        if (!productVo.getStatus().equals(OprProductType.TOINSPECT.getValue())) {
            return warn(barcode.concat(" 非质检状态"));
        }
       /* if (FlagType.HOLDING.in(productVo.getFlag())) {
            return error(barcode.concat("被工单暂停"));
        }*/
        if (productVo.getCompanionId() != null) {
            productVo = oprProductMapper.selectProductVoById(productVo.getCompanionId());
            productVo.setPairBarcode(productVo.getBarcode());
            //productVo.setBarcode(barcode);
        }
        List<OprProductImg> imgs = oprProductImgMapper.selectImgByoprId(productVo.getId());
        imgs.stream().filter(oprProductImg -> oprProductImg.getImgType().equals("1"))
                .forEach(oprProductImg -> oprProductImg.setOprDefeimgList(oprDefeimgMapper.selectDefeByImgId(oprProductImg.getId())));
        Integer flag = productVo.getFlag();
        productVo.setBrandList(stream(MaterialType.values()).filter(s -> s.in(flag)).map(MaterialType::value).collect(Collectors.toList()));
        productVo.setImgList(imgs);
        OprPickup pickup = oprPickupMapper.selectOprPickupById(productVo.getPickupId());
        if(pickup != null){
            productVo.setOrderNo(pickup.getOrderNo());
            productVo.setPickNum(pickup.getChPickupNo());
            if (StringUtils.isNotEmpty(pickup.getComment()) && pickup.getComment().contains("@=@")) {
                String[] split = pickup.getComment().split("@=@");
                if (split.length >= 2) {
                    productVo.setUserComment(split[0]);
                    productVo.setMerchantComment(split[1]);
                }
            }
        }
        productVo.setName(ofNullable(sysProductService.selectSysProductById(productVo.getProductId())).map(SysProduct::getName).orElse(null));
        productVo.setRewashList(oprRewashMapper.selectOprRewashByProductId(productVo.getId()));
        productVo.setPairBarcode(ofNullable(oprProductMapper.selectOprProductByCompanionId(productVo.getId())).map(OprProduct::getBarcode).orElse(null));
        return success(productVo);
    }

    /**
     * 质检--质检合格
     *
     * @param barcode
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult qualified(String barcode, String code) {
        log.info("打印质检合格请求参数--方法::qualified------barcode:[{}],code:[{}]", barcode, code);
        applicationContext.publishEvent(new ReturnOrderEvent(this, barcode)); //质检时触发校验返厂单
        OprProduct oprProduct = OprProduct.builder().barcode(barcode).build();
        ProductVo productVo = oprProductMapper.selectOprProductByBarcode(oprProduct);
        if (productVo == null) {
            throw new ResponseException(barcode + " : 产品不存在");
        }
        if(productVo.getCompanionId() == null){
            if (!productVo.getStatus().equals(TOINSPECT.getValue())){
                throw new ResponseException(barcode + " : 产品状态错误");
            }
        }
        /*if (FlagType.HOLDING.in(productVo.getFlag())) {
            throw new ResponseException(barcode + " : 被工单暂停");
        }*/
        if (StringUtils.isEmpty(code)) {
            if (productVo.getCompanionId() != null) {
                return error(666, "配对的产品需要一同质检");
            } else {
                OprProduct companion = oprProductMapper.selectOprProductByCompanionId(productVo.getId());
                if (companion != null) {
                    return error(666, "配对的产品需要一同质检");
                }
            }
        }
        List<OprAttachment> attachments = new ArrayList<OprAttachment>();
        if (productVo.getCompanionId() != null) {
            attachments = oprAttachmentMapper.queryByProductId(productVo.getCompanionId());
        } else {
            attachments = oprAttachmentMapper.queryByProductId(productVo.getId());
        }
        if (attachments.isEmpty()) {
            oprProduct.setStatus(OprProductType.TOWRAP.getValue());
        } else {
            oprProduct.setStatus(OprProductType.ATTACH.getValue());
        }
        oprProduct.setId(productVo.getId());
        int count = oprProductMapper.updateProductStatusById(oprProduct);
        if(count > 0){
            //保存质检操作记录信息     只保存主产品
            if (productVo.getCompanionId() == null){
                commonPostRecord(PostRecordEnum.QC, productVo.getId());
                //保存产品配附件或者已包装状态改变记录
                commonImportRecord(StatusRecordEnum.PRODUCT, productVo.getId(), oprProduct.getStatus());
                boolean backwash = false;
                int size = oprRewashMapper.selectOprRewashByProductId(oprProduct.getId()).size();
                if (size > 0) {
                    backwash = true;
                }
                //给渠道回写产品配附件或者已包装状态
                if (productVo.getCompanionId() == null) {
                    merchantAsync.backQualState(QualityResult.builder()
                            .pickupNo(oprPickupMapper.selectOprPickupById(productVo.getPickupId()).getChPickupNo())
                            .status(OprProductType.instance(oprProduct.getStatus()).toString())
                            .barcode(barcode)
                            .result("质检合格")
                            .backwash(backwash)
                            .terminate(FlagType.TERMINATE.in(productVo.getFlag()))
                            .code(sysProductService.selectSysProductById(productVo.getProductId()).getCode())
                            .build(), productVo.getChannelId());
                    OprProduct product = queryProductById(productVo.getId());
                    if(oprProduct.getStatus().equals(OprProductType.ATTACH.getValue())){
                        applicationContext.publishEvent(new AttachEvent(this, product));
                    }
                }
            }
        }
        return success();
    }

    @Override
    public AjaxResult pairQualified(String barcode, String pairbarcode) {
        List<String> list = new ArrayList<>();
        list.add(barcode);
        list.add(pairbarcode);
        list.forEach(b -> {
            qualified(b, "(╯°Д°)╯︵ ┻━┻");
        });
        return success();
    }

    @Override
    public AjaxResult stain(String barcode, String pairbarcode) {
        applicationContext.publishEvent(new ReturnOrderEvent(this, barcode)); //质检时触发校验返厂单
        AjaxResult result;
        if (isBlank(pairbarcode)) {
                OprProduct product = oprProductMapper.queryByBarcode(barcode);
                if (product != null) {
                    OprProduct build = OprProduct.builder().barcode(barcode).build();
                    build.setId(product.getId());
                    build.setFlag(FlagType.TERMINATE.value());
                    oprProductMapper.updateStatueById(build);
                }
            result = qualified(barcode, null);
        } else {
            OprProduct product = oprProductMapper.queryByBarcode(barcode);
            if (product != null) {
                OprProduct build = OprProduct.builder().barcode(barcode).build();
                build.setId(product.getId());
                build.setFlag(FlagType.TERMINATE.value());
                oprProductMapper.updateStatueById(build);
                build.setBarcode(pairbarcode);
                oprProductMapper.updateStatueById(build);
            }
            result = pairQualified(barcode, pairbarcode);
        }
        return result;
    }

    /**
     * S3上传图片
     *
     * @param
     */
    @Override
    public JsonObject getUploadCredential() {
        return s3Tool.getUploadCredential();
    }


    /**
     * 质检--反洗
     *
     * @param barcode
     */
    @Override
    public AjaxResult rewash(String barcode, String comment) {
        ProductVo productVo = updateStatus(barcode, OprProductType.TOINSPECT.getValue(), OprProductType.TOWASH.getValue());
        if (productVo == null) {
            return error("产品信息错误");
        }
        /*if (FlagType.HOLDING.in(productVo.getFlag())) {
            return error("被工单暂停");
        }*/
        OprRewash build = OprRewash.builder().productId(productVo.getId()).comment(comment).build();
        build.setCreateBy(getUserName());
        build.setModifyBy(getUserName());
        oprRewashMapper.insertOprRewash(build);
        return success();
    }

    /**
     * 查询产品瑕疵列表
     *
     * @param
     */
    @Override
    public AjaxResult getFlawsList(Long oprProductId) {
        return success(oprDefeimgMapper.selectDefeByProductId(oprProductId));
    }

    /**
     * 打包---取消出厂单
     */
    @Override
    public AjaxResult cancelShipment(String shipmentNo) {
        OprShipment shipment = oprShipmentMapper.queryBychShipmentNo(shipmentNo);
        if (shipment == null) {
            return error("出场单状态错误");
        }
        List<OprProduct> products = oprProductMapper.selectOprProductList(OprProduct.builder()
                .shipmentId(shipment.getId())
                .status(OprProductType.PACKED.getValue())
                .build());
        products.forEach(p -> {
            p.setStatus(OprProductType.PICKED.getValue());
            p.setFlag(null);
            oprProductMapper.updateStatueById(p);
            staProductService.deleteStaProductBystates(StaProduct.builder().productId(p.getId()).status(OprProductType.PACKED.getValue()).build());
            postPackService.deletePostPackByProductId(p.getId());
        });
        shipment.setStatus(ShipMentType.PICKED.getValue());
        oprShipmentMapper.updateOprShipment(shipment);
        staShipmentService.deleteStaShipmentByState(StaShipment.builder().shipmentId(shipment.getId()).status(ShipMentType.PACKING.getValue()).build());
        return success();
    }


    /**
     * 作业产品进洗涤车间
     *
     * @param
     */
    @Override
    public AjaxResult washing(String barcode, boolean flag) {
        ProductVo productVo = updateStatus(barcode, OprProductType.TOWASH.getValue(), OprProductType.WASHING.getValue());
        if (productVo == null) {
            return AjaxResult.warn("产品信息错误");
        }
        /*if (FlagType.HOLDING.in(productVo.getFlag())) {
            return AjaxResult.error("被工单暂停");
        }*/
        return success();
    }

    /**
     * 作业产品出洗涤车间
     *
     * @param
     */
    @Override
    public AjaxResult washed(String barcode, boolean flag) {
        applicationContext.publishEvent(new WashingEvent(this, barcode));//触发进洗涤车间事件
        ProductVo productVo = updateStatus(barcode, OprProductType.WASHING.getValue(), OprProductType.WASHED.getValue());
        if (productVo == null) {
            return AjaxResult.warn("产品信息错误");
        }
        /*if (FlagType.HOLDING.in(productVo.getFlag())) {
            return AjaxResult.error("被工单暂停");
        }*/
        return success();
    }

    /**
     * 作业产品待质检(进行粘毛去球后处理)
     *
     * @param
     */
    @Override
    public AjaxResult toinspect(String barcode, boolean flag) {
        applicationContext.publishEvent(new WashedEvent(this, barcode)); //后处理时触发出洗涤车间事件
        ProductVo productVo = updateStatus(barcode, OprProductType.WASHED.getValue(), OprProductType.TOINSPECT.getValue());
        if (productVo == null) {
            return AjaxResult.warn("产品信息错误");
        }
        /*if (FlagType.HOLDING.in(productVo.getFlag())) {
            return AjaxResult.error("被工单暂停");
        }*/
        return success();
    }

    /**
     * 作业产品拣货
     *
     * @param
     */
    @Override
    public AjaxResult topick(String barcode, boolean flag) {
        ProductVo productVo = updateStatus(barcode, OprProductType.TOPICK.getValue(), OprProductType.PICKED.getValue());
        if (productVo == null) {
            return AjaxResult.warn("产品信息或状态错误");
        }
        /*if (FlagType.HOLDING.in(productVo.getFlag())) {
            return AjaxResult.error("被工单暂停");
        }*/
        if (Objects.isNull(OperateRecordUtil.getPostRecord(PostRecordEnum.SORT, productVo.getId()))) {
            OperateRecordUtil.commonPostRecord(PostRecordEnum.SORT, productVo.getId());
        }
        List<OprProduct> products = oprProductMapper.selectProductByShipmentId(productVo.getShipmentId());
        List<OprProduct> collect = products.stream().filter(p -> p.getStatus().equals(OprProductType.PICKED.getValue())).toList();
        if (collect.size() == products.size()) {
            OprShipment shipment = OprShipment.builder().status(ShipMentType.PICKED.getValue()).build();
            shipment.setId(productVo.getShipmentId());
            oprShipmentMapper.updateOprShipment(shipment);
            //保存出场单已拣货状态改变
            commonImportRecord(StatusRecordEnum.SHIPMENT, shipment.getId(), shipment.getStatus());
            //给渠道回写出厂单已拣货状态
            OprShipment oprShipment = oprShipmentMapper.selectOprShipmentById(productVo.getShipmentId());
            merchantAsync.backShipState(ShipmentStatus.builder()
                    .shipmentNo(oprShipment.getChShipmentNo())
                    .status(ShipMentType.instance(shipment.getStatus()).toString())
                    .build(), oprShipment.getChannelId());
        }
        return success();
    }


    public ProductVo updateStatus(String barcode, String checkStatus, String status) {
        ProductVo productVo = oprProductMapper.selectOprProductByBarcode(OprProduct.builder().barcode(barcode).status(checkStatus).build());
        if (productVo == null) {
            return productVo;
        }
        if (productVo.getCompanionId() != null) {
            productVo = oprProductMapper.selectProductVoById(productVo.getCompanionId());
        }
        OprProduct product = oprProductMapper.selectOprProductByCompanionId(productVo.getId());
        if (product != null) {
            product.setStatus(status);
            product.setFlag(null);
            oprProductMapper.updateOprProduct(product);
        }
        Integer pflag = productVo.getFlag();
        productVo.setStatus(status);
        productVo.setFlag(null);
        int count = oprProductMapper.updateProductInfo(productVo);
        if(count > 0){
            //保存产品状态改变记录
            //commonImportRecord(StatusRecordEnum.PRODUCT, productVo.getId(), status, flag);
            commonImportRecord(StatusRecordEnum.PRODUCT,productVo.getId(),status);
            //给渠道回写产品状态
            if (productVo.getCompanionId() == null) {
                merchantAsync.backProductState(ProductStatus.builder()
                        .pickupNo(oprPickupMapper.selectOprPickupById(productVo.getPickupId()).getChPickupNo())
                        .barcode(barcode)
                        .status(OprProductType.instance(status).toString())
                        .state(0).noWash(false).build(), productVo.getChannelId());
            }
        }
        productVo.setFlag(pflag);
        return productVo;
    }


    /*public String getWashCode(String code) {
        StringBuffer wcode = new StringBuffer(IdUtils.SeqGenerator(code, 7));
        int code1 = eanCode(wcode);
        return wcode.append(code1).toString();

    }


    //生成ean13校验码
    public int eanCode(StringBuffer code) {
        int c1 = 0;
        int c2 = 0;
        int sum = 0;
        int check;
        for (int i = 0; i < 12; i += 2) {
            c1 += (code.charAt(i) - '0');
            c2 += (code.charAt(i + 1) - '0');
        }
        sum = c1 + c2 * 3;
        check = (10 - sum % 10) % 10;
        return check;
    }
*/

    /**
     * 修改入厂单以及所属产品的标签
     *
     * @param pickupId 入场单id
     *                 code 方式 true添加标签  false 删除标签
     *                 flag 标签枚举具体值
     */
    @Override
    public String updatePickupFlag(Long pickupId, boolean code, Integer flag) {
        OprPickup build = OprPickup.builder().build();
        build.setId(pickupId);
        build.setFlag(flag);
        AtomicReference<String> result = new AtomicReference<>("success");
        if (code) {
            oprPickupMapper.updateFlagById(build);
        } else {
            oprPickupMapper.deleteFlagById(build);
        }
        List<OprProduct> products = oprProductMapper.selectProductList(OprProduct.builder().pickupId(pickupId).build());
        products.forEach(p -> {
            String str = updateProductFlag(p, code, flag);
            if (!str.equals("success")) {
                result.set(str);
            }
        });
        return result.get();
    }

    /**
     * 修改出厂单以及所属产品的标签
     *
     * @param shipmentId 出场单id
     *                   code 方式 true添加标签  false 删除标签
     *                   flag 标签枚举具体值
     */
    @Override
    public String updateShipmentFlag(Long shipmentId, boolean code, Integer flag) {
        OprShipment build = OprShipment.builder().build();
        build.setId(shipmentId);
        build.setFlag(flag);
        AtomicReference<String> result = new AtomicReference<>("success");
        if (code) {
            oprShipmentMapper.updateFlagById(build);
        } else {
            oprShipmentMapper.deleteFlagById(build);
        }
        List<OprProduct> products = oprProductMapper.selectOprProductList(OprProduct.builder().shipmentId(shipmentId).build());
        products.forEach(p -> {
            String str = updateProductFlag(p, code, flag);
            if (!str.equals("success")) {
                result.set(str);
            }
        });
        return result.get();
    }

    /**
     * 修改产品的标签
     *
     * @param product 产品名称
     *                code 方式 true添加标签  false 删除标签
     *                flag 标签枚举具体值
     */
    @Override
    public String updateProductFlag(OprProduct product, boolean code, Integer flag) {
        OprProduct build = OprProduct.builder().build();
        build.setId(product.getId());
        build.setFlag(flag);
        build.setBarcode(product.getBarcode());
        int state = 0;
        if (code) {
            oprProductMapper.updateStatueById(build);
            if (flag == FlagType.HOLDING.value()) {
                state = 1;
            }
        } else {
            oprProductMapper.deleteFlagByBarcode(build);
            if (flag == FlagType.HOLDING.value()) {
                state = 2;
            }
        }
        OprPickup pickup = oprPickupMapper.selectOprPickupById(product.getPickupId());
        if (product.getCompanionId() == null) {
            try {
                merchantAsync.backProductState(ProductStatus.builder()
                        .pickupNo(pickup.getChPickupNo())
                        .barcode(product.getBarcode())
                        .status(OprProductType.instance(product.getStatus()).toString())
                        .state(state).noWash(false).build(), pickup.getChannelId());
            } catch (Exception e) {
                log.error("回写产品因工单改变状态失败--error::[{}]", e);
            }
        }
        return "success";
    }

    @Override
    public String holdingOrder(String orderNo, boolean code) {
        log.info("打印请求参数--方法::holdingOrder------orderNo:[{}],code:[{}]", orderNo, code);
        List<OprPickup> pickups = oprPickupMapper.selectOprPickupList(OprPickup.builder().orderNo(orderNo).build());
        if (CollectionUtils.isEmpty(pickups)) {
            return "订单信息错误";
        }
        AtomicReference<String> result = new AtomicReference<>("success");
        pickups.forEach(p -> {
            String str = updatePickupFlag(p.getId(), code, FlagType.HOLDING.value());
            if (!str.equals("success")) {
                result.set(str);
            }
        });
        return result.get();
    }

    /*@Override
    public String notWash(String barcode) {
        log.info("打印请求参数--方法::notWash------barcode:[{}]", barcode);
        OprProduct product = oprProductMapper.queryByBarcode(barcode);
        if (product == null) {
            return "产品信息错误";
        }
        OprProduct build = OprProduct.builder().barcode(barcode).build();
        build.setId(product.getId());
        build.setFlag(FlagType.NOTWASH.value());
        build.setStatus(OprProductType.TOINSPECT.getValue());
        oprProductMapper.updateStatueById(build);
        OprPickup pickup = oprPickupMapper.selectOprPickupById(product.getPickupId());
        if (product.getCompanionId() == null) {
            try {
                String code = merchantAsync.backProductState(ProductStatus.builder()
                        .pickupNo(pickup.getChPickupNo())
                        .barcode(product.getBarcode())
                        .status(OprProductType.instance(product.getStatus()).toString())
                        .state(0).noWash(true).build(), pickup.getChannelId());
            } catch (Exception e) {
                log.error("回写产品因工单改变状态失败--error::[{}]", e);
            }
        }
        return "success";
    }
*/
  /*  @Override
    public AjaxResult loseAttachment(String barcode, List<String> names, String remark) {
        applicationContext.publishEvent(new TicketNoWashEvent(this,barcode,names,remark));
        return success();
    }

    @Override
    public AjaxResult afterSale(String barcode, List<String> imgs, String remark) {
        applicationContext.publishEvent(new TicketHoldingEvent(this,barcode,imgs,remark));
        return success();
    }*/

    @Override
    public AjaxResult getOrderInfo(String barcode) {
        log.info("获取工单详情衣服列表和订单与用户信息----barcode:[{}]",barcode);
        OprPickup pickup;
        String[] barcodes = barcode.split(",");
        List<OprProduct> finalProducts = new ArrayList<OprProduct>();
        stream(barcodes).toList().forEach(b -> {
            OprProduct query = oprProductMapper.queryByBarcode(b);
            if (query == null) {
                throw new ResponseException("水洗码错误");
            }
            if(query.getCompanionId() != null){
                query = oprProductMapper.selectOprProductById(query.getCompanionId());
                if(query == null){
                    throw new ResponseException("鞋子配对信息错误");
                }
            }
          finalProducts.add(query);
        });
        pickup = oprPickupMapper.selectOprPickupById(finalProducts.get(0).getPickupId());
        List<ClothVo> clothVos = new ArrayList<>();
        finalProducts.forEach(p -> {
            String inTime = DateUtils.getDatePoor(p.getCreateAt(),DateUtils.getNowDate());
            if(p.getStatus().equals(OprProductType.SHIPPED.getValue())){
                List<StaProduct> staProducts = staProductService.selectStaProductList(StaProduct.builder()
                        .productId(p.getId())
                        .status(OprProductType.SHIPPED.getValue())
                        .build());
                if(!CollectionUtils.isEmpty(staProducts)){
                    inTime = DateUtils.getDatePoor(p.getCreateAt(),staProducts.get(0).getCreateAt());
                }
            }
            List<OprProductImg> oprProductImgs = oprProductImgMapper.selectImgByoprId(p.getId());
            if(!CollectionUtils.isEmpty(oprProductImgs)){
                oprProductImgs.forEach(i-> i.setOprDefeimgList(oprDefeimgMapper.selectDefeByImgId(i.getId())));
            }
            clothVos.add(ClothVo.builder()
                    .clothName(ofNullable(sysProductService.selectSysProductById(p.getProductId())).map(SysProduct::getName).orElse(null))
                    .barcode(p.getBarcode())
                    .attachment(oprAttachmentMapper.selectAttachmentList(p.getId()).stream().map(OprAttachment::getAttName).collect(joining(",")))
                    .flaws(oprDefeimgMapper.selectDefeByProductId(p.getId()).stream().map(OprDefeimg::getName).collect(joining(",")))
                    .frameNo(p.getFrameNo())
                    .imgs(oprProductImgs)
                    .state(OprProductType.getName(p.getStatus()))
                    .isBack(oprRewashMapper.selectOprRewashByProductId(p.getId()).size())
                    .stop(FlagType.TERMINATE.in(p.getFlag()))
                    .washMode(p.getWashMode())
                    .inTime(inTime)
                    .build());


        });
        SysChannel channel = channelService.selectSysChannelById(pickup.getChannelId());

        //String orderNum = "991997026674470912";
        String brand = null;
        String userPhone = null;
        String userName = null;
        String userComment = null;
        String result = null;
        try {
            result = merchantAsync.getOrderInfo(pickup.getOrderNo(), pickup.getChannelId());
        } catch (Exception e) {
            log.info("channel---getOrderInfo  error:[{}]", e);
        }
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = parseObject(result);
            brand = parseObject(jsonObject.getString("merchant")).getString("name");
            userPhone = jsonObject.getString("phone");
            userName = jsonObject.getString("name");
            userComment = jsonObject.getString("comment");
        }
        return AjaxResult.success(OrderInfo.builder()
                .orderNo(pickup.getOrderNo())
                .brand(brand)
                .source(channel.getName())
                .clothsNum(oprPickupMapper.selectOprPickupList(OprPickup.builder().orderNo(pickup.getOrderNo()).build()).stream().mapToInt(OprPickup::getQuantity).sum())
                .quantity(ofNullable(oprProductMapper.selectProductByOrderNo(pickup.getOrderNo())).map(List::size).orElse(0))
                .userPhone(userPhone)
                .userName(userName)
                .userComment(userComment)
                .clothVos(clothVos)
                .build());
    }

    @Override
    public AjaxResult delOprProduct(Long id) {
        OprProduct build = OprProduct.builder().build();
        build.setId(id);
        build.setFlag(FlagType.DELETE.value());
        int code = oprProductMapper.updateOprProduct(build);
        OprProduct product = oprProductMapper.selectOprProductByCompanionId(id);
        if (product != null) {
            product.setFlag(FlagType.DELETE.value());
            oprProductMapper.updateOprProduct(product);
        }
        if (code == 0) {
            return error();
        }
        return success();
    }

    @Override
    public List<OprProduct> selectByBarcodeAndStatus(String status, PackageQueryPara packageQueryPara) {
        return oprProductMapper.getByBarcodeAndStatus(status, packageQueryPara);
    }

    @Override
    public int selectCountByBarcodeAndStatus(String status, PackageQueryPara para) {
        return oprProductMapper.getCountByBarcodeAndStatus(status, para);
    }

    @Override
    public int updateProduct(OprProduct oprProduct) {
        return oprProductMapper.updateStatueById(oprProduct);
    }

    @Override
    public PageInfo<ClothInfo> getOprProducts(ClothInfo clothInfo) {
        log.info("在厂衣物列表----clothInfo:[{}]",clothInfo);
        List<OprProduct> products = this.selectClothList(clothInfo);
        PageInfo pageInfo = new PageInfo<>(products);
        List<ClothInfo> list = products.stream().map(p -> {
            ClothInfo build = ClothInfo.builder()
                    .barcode(p.getBarcode())
                    .washMode(p.getWashMode())
                    .attachmentInfos(oprAttachmentMapper.selectAttachmentList(p.getId()).stream().map(m-> AttInfo.builder().attName(m.getAttName()).barcode(m.getBarcode()).frameNo(m.getFrameNo()).build()).collect(Collectors.toList()))
                    .flaws(oprDefeimgMapper.selectDefeByProductId(p.getId()).stream().map(OprDefeimg::getName).collect(joining(",")))
                    .name(ofNullable(sysProductService.selectSysProductById(p.getProductId())).map(SysProduct::getName).orElse(null))
                    .checkTime(ofNullable(getPostRecord(PostRecordEnum.QC, p.getId())).map(PostRecord::getCreateAt).map(SIMPLE_DATE_FORMAT::format).orElse(""))
                    .channelName(ofNullable(channelService.selectSysChannelById(p.getChannelId())).map(SysChannel::getName).orElse(null))
                    .pairBarcode(ofNullable(oprProductMapper.selectOprProductByCompanionId(p.getId())).map(OprProduct::getBarcode).orElse(null))
                    .frameNo(p.getFrameNo())
                    .status(getName(p.getStatus()))
                    .channelId(p.getChannelId())
                    .build();
            List<OprProductImg> oprProductImgs = oprProductImgMapper.selectImgByoprId(p.getId());
            if(!CollectionUtils.isEmpty(oprProductImgs)){
                   oprProductImgs.forEach(i-> i.setOprDefeimgList(oprDefeimgMapper.selectDefeByImgId(i.getId())));
            }
            build.setImgs(oprProductImgs);
            if(StringUtils.isNotBlank(clothInfo.getOrderNo())){
                build.setOrderProductNum(oprPickupMapper.selectOprPickupList(OprPickup.builder().orderNo(clothInfo.getOrderNo()).build()).stream().mapToLong(OprPickup::getQuantity).sum());
            }
            OprPickup pickup = oprPickupMapper.selectOprPickupById(p.getPickupId());
            if (pickup != null) {
                List<OprProduct> oprProducts = oprProductMapper.queryByPickupId(pickup.getId());
                build.setProductNum(oprProducts.stream().map(OprProduct::getCompanionId).filter(Objects::isNull).count());
                build.setOrderNo(pickup.getOrderNo());
                List<StaPickup> staPickups = staPickupService.selectStaPickupList(StaPickup.builder().pickupId(pickup.getId()).build());
                if (!CollectionUtils.isEmpty(staPickups)) {
                    staPickups.forEach(s -> {
                        if (s.getStatus().equals(PickupType.SIGNFOFF.getValue())) {
                            build.setSignTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,s.getCreateAt()));
                        }
                        if (s.getStatus().equals(PickupType.RECEIVED.getValue())) {
                            build.setInTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,s.getCreateAt()));
                            build.setDuration(DateUtils.getDatePoor(s.getCreateAt(), DateUtils.getNowDate()));
                        }
                    });
                }

            }
            return build;
        }).collect(Collectors.toList());
        pageInfo.setList(list);
        return pageInfo;
    }

    @Override
    public List<OprProduct> selectClothList(ClothInfo clothInfo) {
        return oprProductMapper.selectClothList(clothInfo);
    }

    @Override
    public List<OprProduct> selectProductByOrderNo(String orderNo) {
        return oprProductMapper.selectProductByOrderNo(orderNo);
    }

    @Override
    public List<OprProductImg> selectImgByProductId(Long productId) {
        return oprProductImgMapper.selectImgByoprId(productId);
    }

    @Override
    public AjaxResult getBarcodeRecord(String barcode) {
        OprProduct product = oprProductMapper.queryByBarcode(barcode);
        if(product == null){
            return AjaxResult.error("水洗码错误");
        }
        List<StaProduct> staProducts = staProductService.selectStaProductList(StaProduct.builder().productId(product.getId()).build());
        staProducts.forEach(s-> s.setStatus(OprProductType.getName(s.getStatus())));
        return AjaxResult.success(staProducts);
    }

    @Override
    public AjaxResult leaveFactory(Long channelId,String washMode,String startTime, String endTime) {
        if(StringUtils.isNotBlank(endTime)){
            Date date = DateUtils.parseDate(endTime);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            Date dateStr = calendar.getTime();
            endTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,dateStr);
        }
        return AjaxResult.success(oprProductMapper.selectLeaveFactoryList(channelId,washMode,startTime,endTime));
    }

    @Override
    public OprProduct selectProductByBarcodeAndStatus(OprProduct oprProduct) {
        return oprProductMapper.selectProductByBarcodeAndStatus(oprProduct);
    }

    @Override
    public OprProduct selectOprProductByMerchandiseId(Long merchandiseId) {
        return oprProductMapper.selectOprProductByMerchandiseId(merchandiseId);
    }

    @Override
    public OprProduct queryByCompanionId(Long companionId) {
        return oprProductMapper.queryByCompanionId(companionId);
    }

    @Override
    public AjaxResult completeCloth(String barcode) {
        ProductVo productVo;
        OprProduct query = oprProductMapper.queryByBarcode(barcode);
        if(query == null){
            return error(ResponseEnum.BARCODE_ERROR.getMessage());
        }
        if(query.getCompanionId() == null){
            productVo = oprProductMapper.selectOprProductByBarcode(OprProduct.builder().barcode(barcode).build());
        }else {
            productVo = oprProductMapper.selectOprProductByBarcode(OprProduct.builder().barcode(ofNullable(oprProductMapper.selectOprProductById(query.getCompanionId())).map(OprProduct::getBarcode).orElse(null)).build());
        }
        if(Integer.parseInt(productVo.getStatus()) > 5){
            return error("水洗码已质检，不符合补拍/补附件条件");
        }
        PickupVo pickupVo = oprPickupMapper.selectPickupVoById(productVo.getPickupId());
        if (pickupVo == null) {
            return error("找不到入场单信息");
        }
        OprProduct product = oprProductMapper.selectOprProductByCompanionId(productVo.getId());
        if (product != null) {
            productVo.setPairBarcode(product.getBarcode());
        }
        List<OprPickup> pickups = oprPickupMapper.selectOprPickupList(OprPickup.builder().channelId(pickupVo.getChannelId()).orderNo(pickupVo.getOrderNo()).build());
        pickupVo.setPickupNum(pickups.size());
        pickupVo.setPickupType(stream(WorkType.explode(pickupVo.getFlag())).toList().stream().map(WorkType::name).collect(Collectors.toList()));
        ofNullable(channelService.selectSysChannelById(pickupVo.getChannelId())).ifPresent(c ->{
            pickupVo.setChannelName(c.getName());
            pickupVo.setChannelCode(c.getCode());
        });
        List<ProductVo> productVos = new ArrayList<>();
        productVo.setBrandList(stream(MaterialType.values()).filter(s -> s.in(productVo.getFlag())).map(MaterialType::value).collect(Collectors.toList()));
        productVo.setImgList(oprProductImgMapper.selectOprProductImgList(OprProductImg.builder().oprProductId(productVo.getId()).build()));
        productVo.setCode(ofNullable(oprMerchandiseMapper.selectOprMerchandiseById(productVo.getMerchandiseId())).map(OprMerchandise::getCode).orElse(null));
        productVo.setName(ofNullable(sysProductService.selectSysProductById(productVo.getProductId())).map(SysProduct::getName).orElse(null));
        productVos.add(productVo);
        pickupVo.setProductVoList(productVos);
        return success(pickupVo);

    }

    @Override
    public AjaxResult complete(CompleteInfo completeInfo) {
        OprProduct product = oprProductMapper.queryByBarcode(completeInfo.getBarcode());
        if(product == null){
           return error(BARCODE_ERROR.getMessage());
        }
        String result = merchantAsync.pushCompleteInfo(CompleteVo.builder()
                .barcode(completeInfo.getBarcode())
                .oprAttachments(completeInfo.getOprAttachments())
                .flawImg(completeInfo.getImgList())
                .pickupNo(ofNullable(oprPickupMapper.selectOprPickupById(product.getPickupId())).map(OprPickup::getChPickupNo).orElse(null))
                .build(), product.getChannelId());
        if (!result.equals("201")) {
            return error("渠道同步失败！请联系管理员");
        }
        ofNullable(completeInfo.getOprAttachments()).ifPresent(attachments -> attachments.forEach(a -> {
            OprAttachment attachment = new OprAttachment();
            attachment.setId(a.getId());
            attachment.setFlag(1);
            oprAttachmentMapper.updateOprAttachment(attachment);
        }));
        ofNullable(completeInfo.getImgList()).ifPresent(imgList -> imgList.forEach(i->{
            OprProductImg build = OprProductImg.builder().imgType("1").build();
            build.setId(i.getId());
            oprProductImgMapper.updateOprProductImg(build);
        }));
        return success();
    }


    @Override
    public List<OprSysProduct> oprSysProductByShipmentId(Long id) {
        return oprProductMapper.oprSysProductByShipmentId(id);
    }



}
